#pragma once
#include "muduo/proto/codec.h"
#include "muduo/proto/dispatcher.h"
#include "muduo/base/Logging.h"
#include "muduo/base/Mutex.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"

#include "mq_connection.hpp"
#include "mq_channel.hpp"
#include "mq_consumer.hpp"
#include "mq_host.hpp"
#include "../common/mq_threadpool.hpp"

#include "../common/mq_msg/mq_msg.pb.h"
#include "../common/mq_proto/mq_proto.pb.h"
#include "../common/log.hpp"

namespace xzt
{
    using namespace std::placeholders;
    #define DBFILE "/data.db"
    #define SERVER_NAME "basichost"
    class Server
    {
        
    public:
        using MessagePtr = std::shared_ptr<google::protobuf::Message>;

        Server(int port, const std::string& basedir) : 
                           _server(
                               &_baseloop,
                               muduo::net::InetAddress("0.0.0.0", port),
                               "Server",
                               muduo::net::TcpServer::kReusePort),
                           _dispatcher(
                               std::bind(&Server::onUnKnownMessage,
                                         this,
                                         _1, _2, _3)),
                           _codec(
                               std::make_shared<ProtobufCodec>(
                               std::bind(&ProtobufDispatcher::onProtobufMessage,
                                         &_dispatcher,
                                         _1, _2, _3))),
                           _host(std::make_shared<VirtualHost>(SERVER_NAME, basedir, basedir + DBFILE)),
                           _consumer_manager(std::make_shared<ConsumerManager>()),
                           _connection_manager(std::make_shared<ConnectionManager>()),
                           _thread_pool(std::make_shared<threadpool>())
        {
            // 记得针对历史数据中的所有队列，初始化队列的消费者管理结构
            QueueMap queue_map = _host->allQueues();
            for (auto& pair : queue_map)
            {
                _consumer_manager->declareQueueConsumer(pair.first);
            }

            // 注册业务处理回调函数
            _dispatcher.registerMessageCallback<xzt::openChannelRequest>(std::bind(
                &Server::onOpenChannel, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::closeChannelRequest>(std::bind(
                &Server::onCloseChannel, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::declareExchangeRequest>(std::bind(
                &Server::onDeclareExchange, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::deleteExchangeRequest>(std::bind(
                &Server::onDeleteExchange, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::declareQueueRequest>(std::bind(
                &Server::onDeclareQueue, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::deleteQueueRequest>(std::bind(
                &Server::onDeleteQueue, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::queueBindRequest>(std::bind(
                &Server::onQueueBind, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::queueUnbindRequest>(std::bind(
                &Server::onQueueUnbind, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::basicPublishRequest>(std::bind(
                &Server::onBasicPublish, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::basicAckRequest>(std::bind(
                &Server::onBasicAck, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::basicConsumeRequest>(std::bind(
                &Server::onBasicConsume, this, _1, _2, _3));
            _dispatcher.registerMessageCallback<xzt::basicCancelRequest>(std::bind(
                &Server::onBasicCancel, this, _1, _2, _3));

            // 将类成员函数设置为服务器的回调处理函数
            _server.setConnectionCallback(
                std::bind(&Server::onConnection, this, _1));
            _server.setMessageCallback(
                std::bind(&ProtobufCodec::onMessage, _codec.get(), _1, _2, _3));
        }

        void start()
        {
            // 开始事件监听
            _server.start();
            // 开始事件监控，这是死循环阻塞接口
            _baseloop.loop();
        }

    private:
        void onUnKnownMessage(const muduo::net::TcpConnectionPtr &conn, const MessagePtr &message, muduo::Timestamp)
        {
            LOG_INFO << "onUnKnownMessage: " << message->GetTypeName();
        }

        void onConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            // 新连接建立成功时的回调函数
            if (conn->connected())
            {
                _connection_manager->newConnection(_host, _consumer_manager, conn, _codec, _thread_pool);
                DLOG("新连接建立成功!");
            }
            else
            {
                _connection_manager->delConnection(conn);
                DLOG("新连接关闭！");
            }
        }

    private:
        // 通过TCP连接和信道ID获取信道对象
        Channel::ptr _getConnectionChannelByTcpAndCid(const muduo::net::TcpConnectionPtr& conn, const std::string& cid)
        {
            // 1.先通过TCP连接找到对应的连接对象
            Connection::ptr p_conn = _connection_manager->getConnection(conn);
            if(p_conn == nullptr)
            {
                ELOG("_getConnectionChannelByTcpAndCid: 连接不存在！");
                conn->shutdown();
                return nullptr;
            }
            // 2.通过信道ID找到连接对象对应的信道对象
            Channel::ptr p_channel = p_conn->getChannel(cid);
            if(p_channel == nullptr)
            {
                ELOG("_getConnectionChannelByTcpAndCid: 信道不存在！");
                conn->shutdown();
                return nullptr;
            }

            return p_channel;
        }
    private:
        // 1.打开信道
        void onOpenChannel(const muduo::net::TcpConnectionPtr &conn, const openChannelRequestPtr &message, muduo::Timestamp)
        {
            Connection::ptr p_conn = _connection_manager->getConnection(conn);
            if(p_conn == nullptr)
            {
                ELOG("openChannel: 连接不存在！");
                conn->shutdown();
                return;
            }
            p_conn->openChannel(message);
        }
        // 2.关闭信道
        void onCloseChannel(const muduo::net::TcpConnectionPtr &conn, const closeChannelRequestPtr &message, muduo::Timestamp)
        {
            Connection::ptr p_conn = _connection_manager->getConnection(conn);
            if(p_conn == nullptr)
            {
                ELOG("closeChannel: 连接不存在！");
                conn->shutdown();
                return;
            }
            p_conn->closeChannel(message);
        }
        // 3.声明交换机
        void onDeclareExchange(const muduo::net::TcpConnectionPtr &conn, const declareExchangeRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->declareExchange(message);
        }
        // 4.删除交换机
        void onDeleteExchange(const muduo::net::TcpConnectionPtr &conn, const deleteExchangeRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->deleteExchange(message);
        }
        // 5.声明队列
        void onDeclareQueue(const muduo::net::TcpConnectionPtr &conn, const declareQueueRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->declareMsgQueue(message);
        }
        // 6.删除队列
        void onDeleteQueue(const muduo::net::TcpConnectionPtr &conn, const deleteQueueRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->deleteMsgQueue(message);
        }
        // 7.绑定队列
        void onQueueBind(const muduo::net::TcpConnectionPtr &conn, const queueBindRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->queueBind(message);
        }
        // 8.解绑队列
        void onQueueUnbind(const muduo::net::TcpConnectionPtr &conn, const queueUnbindRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->queueUnbind(message);
        }
        // 9.发布消息
        void onBasicPublish(const muduo::net::TcpConnectionPtr &conn, const basicPublishRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->basicPublish(message);
        }
        // 10.消息确认
        void onBasicAck(const muduo::net::TcpConnectionPtr &conn, const basicAckRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->basicAck(message);
        }
        // 11.队列消息订阅
        void onBasicConsume(const muduo::net::TcpConnectionPtr &conn, const basicConsumeRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->basicConsume(message);
        }
        // 12.取消队列消息订阅
        void onBasicCancel(const muduo::net::TcpConnectionPtr &conn, const basicCancelRequestPtr &message, muduo::Timestamp)
        {
            if(message == nullptr) { conn->shutdown(); return; }

            auto p_channel = _getConnectionChannelByTcpAndCid(conn, message->cid());

            p_channel->cancelConsume(message);
        }

    private:
        // _baseloop是epoll的事件监控，会进行描述符的事件监控，触发事件后进行io操作
        muduo::net::EventLoop _baseloop;
        // _server用于设置回调函数，告诉服务器收到什么请求该如何处理
        muduo::net::TcpServer _server;
        // 请求分发器对象，要向该对象中注册请求处理函数
        ProtobufDispatcher _dispatcher;
        // protobuf协议处理器，针对收到的请求进行protobuf协议处理
        ProtobufCodecPtr _codec;
        // 虚拟主机对象，用于管理消息队列和交换机
        VirtualHost::ptr _host;
        // 消费者管理器，用于管理消费者
        ConsumerManager::ptr _consumer_manager;
        // 信道管理器，用于管理连接的信道
        ConnectionManager::ptr _connection_manager;
        // 线程池对象，用于处理消息队列的处理请求
        threadpool::ptr _thread_pool;
    };
}
